import datetime
import asyncore
import socket
import logging
import struct 
from collections import deque



class Connecter(asyncore.dispatcher):
    buffer_size = 32768
    byte2short  = struct.Struct('H')
    
    def __init__(self, sock = None):
        asyncore.dispatcher.__init__(self)
        if sock:
            self.socket = sock
        else:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.send_list = deque()
        self.recv_data_list = []
        
        
    def handle_read(self):
        data = self.recv(self.buffer_size)
        bodysize = 0
        while len(data):
            try:
                bodysize  = self.byte2short.unpack(buffer(data, 0, 2))[0]
            except struct.error as e:
                logging.warn('parse head error ' + str(e))
                return
            
            if bodysize > (len(data) - self.byte2short.size):
                logging.warn('package size not match')
                break
            self.recv_data_list.append(data[self.byte2short.size : (self.byte2short.size + bodysize)])
            data = data[(self.byte2short.size + bodysize) : ]
    
    def get_recv_data(self):
        data = self.recv_data_list
        self.recv_data_list = []
        return data
    
    def reset_socket(self):
        if self.socket:
            self.socket.close()
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    
    def pull(self, data):
        if len(data) > self.buffer_size:
            raise ValueError('data length more than 32768')
        
        self.send_list.append(data)
        self.initiate_send()
        
    
        
    def handle_write(self):
        self.initiate_send()
        
    
    def initiate_send(self):
        while self.send_list and self.connected:
            first = self.send_list[0]
            # handle empty string/buffer or None entry
            if not first:
                del self.send_list[0]
                if first is None:
                    self.handle_close()
                    return

            # handle classic producer behavior
            data = self.byte2short.pack(len(first)) + first
            
            try:
                num_sent = self.send(data)
            except socket.error:
                self.handle_error()
                del self.send_list[0]
                return

            if num_sent:
                if num_sent < len(data) :
                    logging.warn('not send all data size'  + str(len(data)))
                    self.send_list[0] = first[num_sent:] 
                    del self.send_list[0]
                    return
            # we tried to send some actual data
            del self.send_list[0]
            return
        
    def log_info(self, message, type='info'):
        logging.log(logging._levelNames[type.upper()], message)
    
if __name__ == '__main__':
    c = Connecter()
    c.connect(('google.com', 11111))
    asyncore.loop()
    print(c.socket)
    
    print(datetime.datetime.now())
    c.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    c.connect(('google.com', 11111))
    asyncore.loop()
    print(datetime.datetime.now())
